﻿/**
 * Copyright(c) Live2D Inc. All rights reserved.
 *
 * Use of this source code is governed by the Live2D Open Software license
 * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
 */

#include "../include/Live2dView.hpp"
#include <math.h>
#include <string>
#include "../include/Live2dPal.hpp"
#include "../include/Live2dDelegate.hpp"
#include "../include/Live2dModelManager.hpp"
#include "../include/Live2dTextureManager.hpp"
#include "../include/Live2dDefine.hpp"
#include "../include/Live2dModel.hpp"

using namespace std;
using namespace Live2dDefine;

Live2dView::Live2dView():
    _programId(0),
    _renderTarget(SelectTarget_None)
{
    _clearColor[0] = 1.0f;
    _clearColor[1] = 1.0f;
    _clearColor[2] = 1.0f;
    _clearColor[3] = 0.0f;

    // デバイス座標からスクリーン座標に変換するための
    _deviceToScreen = new CubismMatrix44();

    // 画面の表示の拡大縮小や移動の変換を行う行列
    _viewMatrix = new CubismViewMatrix(); 
}

Live2dView::~Live2dView()
{
    _renderBuffer.DestroyOffscreenFrame();
    delete _viewMatrix;
    delete _deviceToScreen;
}

void Live2dView::Initialize()
{
    int width, height;
    glfwGetWindowSize(Live2dDelegate::GetInstance()->GetWindow(), &width, &height);

    if(width==0 || height==0)
    {
        return;
    }

    float ratio = static_cast<float>(height) / static_cast<float>(width);
    float left = ViewLogicalLeft;
    float right = ViewLogicalRight;
    float bottom = -ratio;
    float top = ratio;

    _viewMatrix->SetScreenRect(left, right, bottom, top); // デバイスに対応する画面の範囲。 Xの左端, Xの右端, Yの下端, Yの上端

    float screenW = fabsf(left - right);
    _deviceToScreen->LoadIdentity(); // サイズが変わった際などリセット必須
    _deviceToScreen->ScaleRelative(screenW / width, -screenW / width);
    _deviceToScreen->TranslateRelative(-width * 0.5f, -height * 0.5f);

    // 表示範囲の設定
    _viewMatrix->SetMaxScale(ViewMaxScale); // 限界拡大率
    _viewMatrix->SetMinScale(ViewMinScale); // 限界縮小率

    // 表示できる最大範囲
    _viewMatrix->SetMaxScreenRect(
        ViewLogicalMaxLeft,
        ViewLogicalMaxRight,
        ViewLogicalMaxBottom,
        ViewLogicalMaxTop
    );
}

void Live2dView::Render()
{

    Live2dModelManager* Live2DManager = Live2dModelManager::GetInstance();

    // Cubism更新・描画
    Live2DManager->OnUpdate();

    // 各モデルが持つ描画ターゲットをテクスチャとする場合
    if (_renderTarget == SelectTarget_ModelFrameBuffer)
    {
        const GLfloat uvVertex[] =
        {
            1.0f, 1.0f,
            0.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
        };

        for (csmUint32 i = 0; i < Live2DManager->GetModelNum(); i++)
        {
            Live2dModel *model = Live2DManager->GetModel(i);
            if (model)
            {
              //tode 绘制帧缓冲
            }
        }
    }
    else if (_renderTarget == SelectTarget_ViewFrameBuffer) 
    {       

    }
}

void Live2dView::StartMotion(const char* group, const int id)
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->StartMotion(group, id);
}

void Live2dView::SetExpression(const char* expression)
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->SetExpression(expression);
}

void Live2dView::SetExpressionById(const int id)
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->SetExpressionById(id);
}

void Live2dView::SetSpeed(const float speed)
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->SetSpeed(speed);
}

void Live2dView::SetRandomMotion(const bool random, const bool randomExpression)
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->SetRandomMotion(random, randomExpression);
}

void Live2dView::OnMouseMoved(float px, float py) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnMove(px, py);
}

void Live2dView::OnMouseClick(int key, bool key_up) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnClick(key,key_up);
}

void Live2dView::OnLeftHandDown(bool key_up) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnLeftHandDown(key_up);
}

void Live2dView::OnRightHandDown(bool key_up) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnRightHandDown(key_up);
}

void Live2dView::OnStickLeftDown(bool key_up) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnStickLeftDown(key_up);
}

void Live2dView::OnStickRightDown(bool key_up) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnStickRightDown(key_up);
}

void Live2dView::OnStickShowLeftHand(bool key_up) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnStickShowLeftHand(key_up);
}

void Live2dView::OnStickShowRightHand(bool key_up) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnStickShowRightHand(key_up);
}

void Live2dView::OnStickL(float x, float y) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnStickL(x,y);
}

void Live2dView::OnStickR(float x, float y) const
{
    Live2dModelManager* _live2dModelManager = Live2dModelManager::GetInstance();
    _live2dModelManager->OnStickR(x,y);
}

bool Live2dView::ScaleView(float s_x, float s_y) const
{
    if (s_x <= 0 || s_y <= 0)
        return false;
   
    _viewMatrix->Scale(s_x,s_y);
    return true;
}

bool Live2dView::TranslateView(float t_x, float t_y) const
{
    _viewMatrix->Translate(t_x, t_y);
    return true;
}

float Live2dView::TransformViewX(float deviceX) const
{
    float screenX = _deviceToScreen->TransformX(deviceX); // 論理座標変換した座標を取得。
    return _viewMatrix->InvertTransformX(screenX); // 拡大、縮小、移動後の値。
}

float Live2dView::TransformViewY(float deviceY) const
{
    float screenY = _deviceToScreen->TransformY(deviceY); // 論理座標変換した座標を取得。
    return _viewMatrix->InvertTransformY(screenY); // 拡大、縮小、移動後の値。
}

float Live2dView::TransformScreenX(float deviceX) const
{
    return _deviceToScreen->TransformX(deviceX);
}

float Live2dView::TransformScreenY(float deviceY) const
{
    return _deviceToScreen->TransformY(deviceY);
}

void Live2dView::PreModelDraw(Live2dModel& refModel)
{
    // 別のレンダリングターゲットへ向けて描画する場合の使用するフレームバッファ
    Csm::Rendering::CubismOffscreenFrame_OpenGLES2* useTarget = NULL;

    if (_renderTarget != SelectTarget_None)
    {// 別のレンダリングターゲットへ向けて描画する場合

        // 使用するターゲット
        useTarget = (_renderTarget == SelectTarget_ViewFrameBuffer) ? &_renderBuffer : &refModel.GetRenderBuffer();

        if (!useTarget->IsValid())
        {// 描画ターゲット内部未作成の場合はここで作成
            int width, height;
            glfwGetWindowSize(Live2dDelegate::GetInstance()->GetWindow(), &width, &height);
            if (width != 0 && height != 0)
            {
                // モデル描画キャンバス
                useTarget->CreateOffscreenFrame(static_cast<csmUint32>(width), static_cast<csmUint32>(height));
            }
        }

        // レンダリング開始
        useTarget->BeginDraw();
        useTarget->Clear(_clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]  ); // 背景クリアカラー
    }
}

void Live2dView::PostModelDraw(Live2dModel& refModel)
{
    // 別のレンダリングターゲットへ向けて描画する場合の使用するフレームバッファ
    Csm::Rendering::CubismOffscreenFrame_OpenGLES2* useTarget = NULL;

    if (_renderTarget != SelectTarget_None)
    {// 別のレンダリングターゲットへ向けて描画する場合

        // 使用するターゲット
        useTarget = (_renderTarget == SelectTarget_ViewFrameBuffer) ? &_renderBuffer : &refModel.GetRenderBuffer();

        // レンダリング終了
        useTarget->EndDraw();

        // LAppViewの持つフレームバッファを使うなら、スプライトへの描画はここ
        if (_renderTarget == SelectTarget_ViewFrameBuffer)
        {
            const GLfloat uvVertex[] =
            {
                1.0f, 1.0f,
                0.0f, 1.0f,
                0.0f, 0.0f,
                1.0f, 0.0f,
            };
        }
    }
}

void Live2dView::SwitchRenderingTarget(SelectTarget targetType)
{
    _renderTarget = targetType;
}

void Live2dView::SetRenderTargetClearColor(float r, float g, float b)
{
    _clearColor[0] = r;
    _clearColor[1] = g;
    _clearColor[2] = b;
}

void Live2dView::SetRenderBufferTarget(GLuint id, uint32_t displayBufferWidth, uint32_t displayBufferHeight)
{
    _renderBuffer.CreateOffscreenFrame(displayBufferWidth, displayBufferHeight, id);
}



